/***************************************************************************
 *   Copyright (C) 2007 by Pablo Antolín  				   *
 *   pablo.antolin@madrimasd.net   					   *
 *                                                                         *
 *   This program is free software; you can redistribute it and/or modify  *
 *   it under the terms of the GNU General Public License as published by  *
 *   the Free Software Foundation; either version 2 of the License, or     *
 *   (at your option) any later version.                                   *
 *                                                                         *
 *   This program is distributed in the hope that it will be useful,       *
 *   but WITHOUT ANY WARRANTY; without even the implied warranty of        *
 *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the         *
 *   GNU General Public License for more details.                          *
 *                                                                         *
 *   You should have received a copy of the GNU General Public License     *
 *   along with this program; if not, write to the                         *
 *   Free Software Foundation, Inc.,                                       *
 *   59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.             *
 ***************************************************************************/


#include <unistd.h>   // esta es para usar unlink y close con el socket
#include <iostream>
#include <sys/types.h>
#include <sys/socket.h>
#include <sys/un.h>	
#include <fcntl.h>   //para el bloqueo
#include <vector>

using namespace std;

class GmcSocket
{

public:

	GmcSocket();		   //constuctor de socket cliente con bloqueo

	GmcSocket(const char *) ;  //constructor de socket servidor con bloqueo

	GmcSocket(int);		   //constructor de socket cliente sin bloqueo

	GmcSocket(const char *, int);  //constructor de socket servidor sin bloqueo

	~GmcSocket();	

	void unlink_path();		//libera la dirección asociada al socket servidor

	void set_nonblock();

	void set_send_path(const char *);  //asignación de dirección de envío

	void set_recv_path(const char *);  //asignación de dirección de envío

	int receive();			
	
	int send(double *);	

	int send(double *, int);

	int send(float *);	

	int send(float *, int);

	int send(int *);

	int send(int *, int);

	int send(const char *);

	int send(const char *, int);
	
	std::vector< sockaddr_un > addresses;   //creo un vector de objetos de la clase sockaddr_un

	char buffer[1024];

	
private:

	int s,i;
	char saved_path[100];	
};




inline GmcSocket::GmcSocket(const char *path)
{
s= socket(AF_UNIX, SOCK_DGRAM,0);    //ES UN SOCKET PARA UNIX Y UDP
if(s==-1) cout<<"GmcSocket: Error abriendo socket." <<endl<<endl;

sockaddr_un direction;     
sockaddr &directionCast= (sockaddr &) direction;  
bzero(&direction, sizeof(direction));
direction.sun_family = AF_UNIX;
unlink(path);   //libera la dirección de path de cualquier otro socket que antes la utilizara
strcpy(direction.sun_path,path);
strcpy(saved_path,path);
int bin=bind(s, &directionCast, sizeof(direction));
if(bin==-1) cout<<"GmcSocket: Error uniendo dirección."<<endl<<endl;
i=0;
}

inline GmcSocket::GmcSocket()
{
s= socket(AF_UNIX, SOCK_DGRAM,0);  //ES UN SOCKET PARA UNIX Y UDP
if(s==-1)
cout<<"GmcSocket: Error abriendo socket."<<endl<<endl;
i=0;
}

inline GmcSocket::GmcSocket(const char *path,int flag)
{
s= socket(AF_UNIX, SOCK_DGRAM,0);    //ES UN SOCKET PARA UNIX Y UDP
if(s==-1) cout<<"GmcSocket: Error abriendo socket."<<endl<<endl;
if(flag==1) fcntl(s, F_SETFL, O_NONBLOCK); //evita el bloqueo

sockaddr_un direction;     
sockaddr &directionCast= (sockaddr &) direction;  
bzero(&direction, sizeof(direction));
direction.sun_family = AF_UNIX;
unlink(path);  //libera la dirección de path de cualquier otro socket que antes la utilizara
strcpy(direction.sun_path,path);
strcpy(saved_path,path);

int bin=bind(s, &directionCast, sizeof(direction));
if(bin==-1) cout<<"GmcSocket: Error uniendo dirección."<<endl<<endl;
i=0;
}

inline GmcSocket::GmcSocket(int flag)
{
s= socket(AF_UNIX, SOCK_DGRAM,0);  //ES UN SOCKET PARA UNIX Y UDP
if(s==-1)
cout<<"GmcSocket: Error abriendo socket."<<endl<<endl;
if( flag==1) fcntl(s, F_SETFL, O_NONBLOCK);  //evita el bloqueo
i=0;
}

inline GmcSocket::~GmcSocket()
{
unlink(saved_path);
};

inline void GmcSocket::unlink_path()
{
unlink(saved_path);
}

inline void GmcSocket::set_nonblock()
{
fcntl(s, F_SETFL, O_NONBLOCK); //evita el bloqueo
}

inline void GmcSocket::set_send_path(const char *path)
{
addresses.push_back( *(new sockaddr_un) );

bzero(&addresses[i], sizeof(addresses[i]) );
addresses[i].sun_family = AF_UNIX;
strcpy(addresses[i].sun_path,path);
i=i+1;
}

inline void GmcSocket::set_recv_path(const char *path)
{
sockaddr_un direction;     
sockaddr &directionCast= (sockaddr &) direction;  
bzero(&direction, sizeof(direction));
direction.sun_family = AF_UNIX;
unlink(path);   //libera la dirección de path de cualquier otro socket que antes la utilizara
strcpy(direction.sun_path,path);
strcpy(saved_path,path);
int bin=bind(s, &directionCast, sizeof(direction));
if(bin==-1) cout<<"GmcSocket: Error uniendo dirección."<<endl<<endl;
}

inline int GmcSocket::send(double *value)
{
int m;

m=sendto(s,(char *) value, strlen((char *)value),0,&((sockaddr &) addresses[0]), sizeof(addresses[0]) );

if(m==-1)
{
cout <<"GmcSocket: Error enviando datos a la dirección 0."<<endl<<endl;
return m;
}

else 
return 1;

}

inline int GmcSocket::send(double *value, int number)
{
int m;

m=sendto(s,(char *) value,strlen((char *)value),0,&((sockaddr &) addresses[0]), sizeof(addresses[0]) );
if(m==-1) 
{
cout <<"GmcSocket: Error enviando datos a la dirección "<< number<<"."<<endl<<endl;
return m;
}

else
return 1;

}

inline int GmcSocket::send(float *value)
{
int m;

m=sendto(s,(char *) value, strlen((char *)value),0,&((sockaddr &) addresses[0]), sizeof(addresses[0]) );

if(m==-1) 
{
cout <<"GmcSocket: Error enviando datos a la dirección 0."<<endl<<endl;
return m;
}

else
return 1;

}

inline int GmcSocket::send(float *value, int number)
{
int m;

m=sendto(s,(char *) value,strlen((char *)value),0,&((sockaddr &) addresses[0]), sizeof(addresses[0]) );
if(m==-1) 
{
cout <<"GmcSocket: Error enviando datos a la dirección "<< number<<"."<<endl<<endl;
return m;
}

else
return 1;

}

inline int GmcSocket::send(int *value)
{
int m;
m=sendto(s,(char *) value, strlen((char *)value),0,&((sockaddr &) addresses[0]), sizeof(addresses[0]));
if(m==-1) 
{
cout <<"GmcSocket: Error enviando datos a la dirección 0."<<endl<<endl;
return m;
}

else
return 1;

}

inline int GmcSocket::send(int *value, int number)
{
int m;
m=sendto(s,(char *) value, strlen((char *)value),0,&((sockaddr &) addresses[0]), sizeof(addresses[0]));
if(m==-1) 
{
cout <<"GmcSocket: Error enviando datos a la dirección "<< number<<"."<<endl<<endl;
return m;
}

else
return 1;

}

inline int GmcSocket::send(const char *path)
{
int m;

m=sendto(s,path,strlen(path),0,&( (sockaddr &) addresses[0]), sizeof(addresses[0] ) );
if(m==-1) 
{
cout <<"GmcSocket: Error enviando datos a la dirección 0."<<endl<<endl;
return m;
}

else
return 1;

}

inline int GmcSocket::send(const char *path, int number)
{
int m;

m=sendto(s, path,strlen(path),0,&((sockaddr &) addresses[number]), sizeof(addresses[number]));
if(m==-1) 
{
cout <<"GmcSocket: Error enviando datos a la dirección "<<number<<"."<<endl<<endl;
return m;
}

else
return 1;

}

inline int GmcSocket::receive()
{
int m;
bzero(buffer,sizeof(buffer));
m=recvfrom(s,buffer,sizeof(buffer),0,(sockaddr *) NULL, NULL);
if(m>0) return 1;

else return -1;

};


